package org.lilred.ui.theme;

import java.util.Vector;

import net.rim.device.api.ui.Graphics;

public class Theme {
	//Attributes
	protected int backColor = 0xFFFFFF;
	protected int borderColor = 0x000000;
	protected int foreColor = 0x000000;
	protected int textureAlpha = 80;
	protected boolean borderLeft = true;
	protected boolean borderTop = true;
	protected boolean borderRight = true;
	protected boolean borderBottom = true;
	protected int borderWidth = 1;
	protected int borderRadius = 0;
	protected Texture texture = null; 
	private Vector arcPoints;

	// Getters
	public int getBackColor() { return backColor; }
	public int getBorderColor() { return borderColor; }
	public int getForeColor() { return foreColor; }
	public int getTextureAlpha() { return textureAlpha; }
	public boolean hasBorderTop() { return borderTop; }
	public boolean hasBorderLeft() { return borderLeft; }
	public boolean hasBorderBottom() { return borderBottom; }
	public boolean hasBorderRight() { return borderRight; }
	public int getBorderWidth() { return borderWidth; }
	public int getBorderRadius() { return borderRadius; }
	public Texture getTexture() { return texture; }

	// Setters
	public void setBackColor(int color) { backColor = color; }
	public void setBorderColor(int color) { borderColor = color; }
	public void setForeColor(int color) { foreColor = color; }
	public void setTextureAlpha(int alpha) { textureAlpha = alpha; }
	public void setBorderTop(boolean border) { borderTop = border; }
	public void setBorderLeft(boolean border) { borderLeft = border; }
	public void setBorderBottom(boolean border) { borderBottom = border; }
	public void setBorderRight(boolean border) { borderRight = border; }
	public void setBorderWidth(int width) { borderWidth = width; }
	public void setBorderRadius(int radius) { 
		borderRadius = radius; 
		if (borderRadius > 0) calculateArcPoints();
	}
	public void setTexture(Texture t) { texture = t; }
	
	public Theme clone() {
		return new Theme() {
			{
				setBackColor(Theme.this.backColor);
				setBorderColor(Theme.this.borderColor);
				setForeColor(Theme.this.foreColor);
				setTextureAlpha(Theme.this.textureAlpha);
				setBorderLeft(Theme.this.borderLeft);
				setBorderTop(Theme.this.borderTop);
				setBorderRight(Theme.this.borderRight);
				setBorderBottom(Theme.this.borderBottom);
				setBorderWidth(Theme.this.borderWidth);
				setBorderRadius(Theme.this.borderRadius);
				setTexture(Theme.this.texture);
			}
		};
	}

	public void paint(int width, int height, Graphics g) {
		g.setColor(backColor);
		g.fillRect(0, 0, width, height);

		//Draw the texture
		if (texture != null) {
			int oldTexture = g.getGlobalAlpha();
			g.setGlobalAlpha(textureAlpha);
			texture.paint(width, height, g);
			g.setGlobalAlpha(oldTexture);
		}

		//Draw the border
		g.setColor(borderColor);
		for (int i = 0; i < borderWidth; i++) {
			if (borderTop) g.drawLine(0, 0 + i, width, 0 + i); //Top
			if (borderLeft) g.drawLine(0 + i, 0, 0 + i, height); //Left
			if (borderRight) g.drawLine(width - 1 - i, 0, width - 1 - i, height); //Right
			if (borderBottom) g.drawLine(0, height - 1 - i, width, height - 1 - i); //Bottom
		}

		//Cut out the area behind the rounded edges & draw the border
		if (borderRadius > 0) {
			if (borderLeft && borderTop)
				for(int i = 0; i < arcPoints.size(); i++) { //NW 
					Point p = (Point) arcPoints.elementAt(i);
					g.clear(0, p.y,	p.x, 1);
					g.drawPoint(p.x, p.y);
				}
			if (borderTop && borderRight)
				for(int i = 0; i < arcPoints.size(); i++) { //NE
					Point p = (Point) arcPoints.elementAt(i);
					g.clear(width - 1 - p.x, p.y, p.x + 1, 1);
					g.drawPoint(width - 1 - p.x, p.y);
				}
			if (borderBottom && borderLeft)
				for(int i = 0; i < arcPoints.size(); i++) { //SW
					Point p = (Point) arcPoints.elementAt(i);
					g.clear(0, height - 1 - p.y, p.x, 1);
					g.drawPoint(p.x, height - 1 - p.y);
				}
			if (borderBottom && borderRight)
				for(int i = 0; i < arcPoints.size(); i++) { //SE
					Point p = (Point) arcPoints.elementAt(i);
					g.clear(width - 1 - p.x, height - 1 - p.y, p.x + 1, 1);
					g.drawPoint(width - 1 - p.x, height - 1 - p.y);
				}
		}
		g.setColor(foreColor);
	}

	public void calculateArcPoints()
	{
		arcPoints = new Vector();

		int x = 0;
		int y = borderRadius;
		int p = (5 - borderRadius*4)/4;

		circlePoints(borderRadius, borderRadius, x, y);
		while (x < y) {
			x++;
			if (p < 0) {
				p += 2*x+1;
			} else {
				y--;
				p += 2*(x-y)+1;
			}
			circlePoints(borderRadius, borderRadius, x, y);
		}
	}

	private void circlePoints(int cx, int cy, int x, int y)
	{
		if (x == 0) {
			arcPoints.addElement(new Point(cx, cy - y));
			arcPoints.addElement(new Point(cx - y, cy));        		
		} else if (x == y) {
			arcPoints.addElement(new Point(cx - x, cy - y));
		} else if (x < y) {
			arcPoints.addElement(new Point(cx - x, cy - y));
			arcPoints.addElement(new Point(cx - y, cy - x));
			for (int i = 1; i < borderWidth; i++) {
				arcPoints.addElement(new Point(cx - x, cy - y + i));
				arcPoints.addElement(new Point(cx - y + i, cy - x));
			}
		}
	}

	public class Point {
		public int x;
		public int y;
		public Point(int x, int y) {
			this.x = x;
			this.y = y;
		}
	}

}
